<?php
namespace ChannelThrift\Processor;

use ChannelThrift\Service\AddressService;
use ChannelThrift\Service\BailCacheService;
use ChannelThrift\Service\CarModelService;
use ChannelThrift\Service\SystemLogService;
use \Common\Org\PhpRedis;
use \Common\Org\PhpMemcache;

use \Services\AuctionService\AuctionServiceIf;
use \Services\AuctionService\InvalidException;

use \ChannelThrift\Service\BidLogService;
use \ChannelThrift\Service\BiddingLogService;
use \ChannelThrift\Service\CarDealerService;
use \ChannelThrift\Service\DealerBailLogService;
use \ChannelThrift\Service\DealerLogService;
use \ChannelThrift\Service\OrderService;
use \ChannelThrift\Service\SystemConfService;
use \ChannelThrift\Service\AutoBiddingService;
use \ChannelThrift\Service\AutoBiddingLogService;
use \ChannelThrift\Service\AntNestService;

use \ChannelThrift\Service\CarService;
use \ChannelThrift\Service\CarSourceService;
use \ChannelThrift\Service\SceneService;
use \Services\AuctionService\inParamsCreateEditScene;
use \Services\AuctionService\inParamsCreateOrder;

use \Services\AuctionService\BidMsg;
use \Services\AuctionService\BiddingMsg;
use \Services\AuctionService\OrderSceneMsg;
use \Services\AuctionService\InParamsBidding;

class AuctionService implements AuctionServiceIf
{

    private $redis;
    private $mem;
    private $exceptionCode = array();

    public function __construct()
    {
        $this->redis = new PhpRedis();
        $this->mem = new PhpMemcache();
        $this->exceptionCode = C('EXCEPTION_CODE');
    }

    /**
     * 投标出价
     * @param int $dealer_id
     * @param int $order_id
     * @param float $price
     * @param int $dev_type
     * @return array|\Services\AuctionService\BidMsg
     * @throws \Services\AuctionService\InvalidException
     */
    public function bid($dealer_id, $order_id, $price, $dev_type=0)
    {
        //基本数据验证
        if (empty($order_id)) {
            make_throw(700002);
        }
        if (empty($dealer_id)) {
            make_throw(500001);
        }
        if (empty($price)) {
            make_throw(700005);
        }

        //获取保证金配置
        $sysConfServ = new SystemConfService();
        $sysConfInfo = $sysConfServ->getConfByName('BAIL');
        $bail  = $sysConfInfo['value'];

        //获取车商信息
        $carDealerService = new CarDealerService();
        $dealerInfo = $carDealerService->getCarDealer($dealer_id);
        if(empty($dealerInfo)){
            trace('投标出价，获取蚁巢车商账号失败','','ERR',true);
            make_throw(360011);
        }

        if($dealerInfo['status']!=1){//账号禁用不能出价
            make_throw(130006);
        }elseif($dealerInfo['level']==0){//初级买家不能出价
            make_throw(360012);
        }
        //判断保证金
        $dealerBailLogService = new DealerBailLogService();
        $bailLog = $dealerBailLogService->getDealerBailLog($dealer_id, $order_id, 2, 0);

        if(empty($bailLog)){
            if ($dealerInfo['bail_amount'] < $bail) { //保证金不足不可以出价
                make_throw(500051);
            }
        }

        //检查价格是否合法
        $orderServ = new OrderService();
        $order = $orderServ->getOrder($order_id);

        if ($price <= $order['bid_start_price']) {
            make_throw(700007);
        }
        //检查拍单状态是否为投标中
        if ($order['status'] != '3') {
            make_throw(700041);
        }
        if ($price > $order['reserve_price'] * 1.2) {
            make_throw(700033);
        }

        $data = array();
        $data['order_id'] = $order_id;
        $data['dealer_id'] = $dealer_id;
        $data['price'] = $price;
        $data['createtime'] = date('Y-m-d H:i:s');
        $data['dev_type'] = $dev_type;

        $code = 200;
        $msg = '投标出价';

        try {

            //冻结保证金
            $dealerBailLogService = new DealerBailLogService();
            $bailLog = $dealerBailLogService->getDealerBailLog($dealer_id, $order_id, 2, 0);

            if(empty($bailLog)){
                /**冻结当前车商保证金**/
                try{
                    $bailService = new BailService();
                    $freePrice = $bailService->freezeBail($dealer_id,$bail,$order_id);
                    if($freePrice->code!='000000'){
                        trace('order_id:'.$order_id.',冻结车商'.$dealer_id.'保证金失败。','','ERR',true);
                        make_throw($freePrice->code,$freePrice->message);
                    }
                }catch(\Exception $e){
                    trace('投标出价冻结保证金捕获异常：'.$e->getMessage(),'','ERR',true);
                    make_throw($e->getCode(),$e->getMessage());
                }
            }

            //新增投标出价记录
            $bidLogServ = new BidLogService();
            $res = $bidLogServ->InsertBidLog($data);

            if (!$res) {
                $code = '100066';
                $msg = '投标出价失败';
                trace($msg,'','ERR',true);
            }
            //更新车商出价信息
            $carDealerServ = new CarDealerService();
            $carDealerServ->dealerBidPrice($dealer_id,$order_id,$price);

            //新增车商操作日志
            $bidLogServ = new DealerLogService();
            $log = array('order_id' => $order_id, 'dealer_id' => $dealer_id, 'action' => $msg . ',price:' . $price, 'createtime' => date('Y-m-d H:i:s'));
            $bidLogServ->InsertDealerLog($log);

        }catch (\Exception $e){
            $code = $e->getCode();
            $msg = $e->getMessage();
            trace('投标出价捕获异常：'.$msg,'','ERR',true);
        }

        //weaver标准化返回
        $bidMsg = new BidMsg();
        $bidMsg->code = $code;
        $bidMsg->message = $msg;
        return $bidMsg;
    }

    /**
     * 竞拍出价
     * @param InParamsBidding $inParamsBidding
     * @return bool
     * @throws \Services\AuctionService\InvalidException
     */
    public function bidding(InParamsBidding $inParamsBidding)
    {
        global $origin_price_lock_key, $bidding_end_lock_key, $ulock_key, $ulock_key1;

        $paramers               = [];
        $paramers['dealer_id']  = $inParamsBidding->dealerId;
        $paramers['order_id']   = $inParamsBidding->orderId;
        $paramers['org_price']  = $inParamsBidding->basePrice;
        $paramers['add_price']  = $inParamsBidding->addPrice;
        $paramers['price']      = $inParamsBidding->price;
        $paramers['dev_type']   = $inParamsBidding->deviceType;
        $paramers['is_auto']    = $inParamsBidding->isAuto;

        //redis keys
        $arr = ['order_id' => $paramers['order_id']];
        $bidding_end_lock_key = getRedisKeyByCode('REDIS_KEY', '100025', $arr);//竞拍结束锁
        $origin_price_lock_key = getRedisKeyByCode('REDIS_KEY', '100009', $arr);//基价锁key

        $arr = ['dealer_id' => $paramers['dealer_id']];
        $ulock_key = getRedisKeyByCode('REDIS_KEY', '100010', $arr);//1秒频繁出价锁
        $ulock_key1 = getRedisKeyByCode('REDIS_KEY', '100011', $arr);//1秒频繁出价锁

        try {
            //出价条件检查
            $this->preCheck($paramers);

            //该价是否已出过
            $arr = [];
            $arr['order_id']  = $paramers['order_id'];
            $arr['dealer_id'] = $paramers['dealer_id'];
            $arr['price']     =  ($paramers['org_price']==0 && $paramers['add_price']==0) ? $paramers['price'] : ($paramers['org_price']+$paramers['add_price']);
            $biddingCacheKey = getRedisKeyByCode('REDIS_KEY', '100032',$arr);
            if($this->redis->exists($biddingCacheKey)){
                trace(var_export($arr,true),'','INFO',true);
                make_throw(700053);
            }
            //入队
            $biddingInfo = [];
            $biddingInfo['orderId']        = intval($paramers['order_id']);
            $biddingInfo['dealerId']       = intval($paramers['dealer_id']);
            $biddingInfo['orgPrice']       = floatval($paramers['org_price']);
            $biddingInfo['addPrice']       = floatval($paramers['add_price']);
            $biddingInfo['price']          = floatval($paramers['price']);
            $biddingInfo['devType']        = intval($paramers['dev_type']);
            $biddingInfo['isAuto']         = $paramers['is_auto']?true:false;
            $biddingInfo['biddingTime']    = ms_time();

            $biddingKey = getRedisKeyByCode('REDIS_KEY', '100031');
            $this->redis->lpush($biddingKey, json_encode($biddingInfo));
            $this->redis->set($biddingCacheKey, 1,time_left_to_24());//

            //拍单锁（基价锁）解锁
            $this->redis->unlock($origin_price_lock_key);

        } catch (\Exception $e) {
            try {
                //拍单锁（基价锁）解锁
                $this->redis->unlock($origin_price_lock_key);
                if ($e->getCode() != '700044') {//解除1S内频繁出价限制
                    $this->redis->unlock($ulock_key1);
                }
            } catch (\Exception $e1) {
                throw new InvalidException(array('code' => $e1->getCode(), 'message' => $e1->getMessage()));
            }
            //抛出异常结客户端
            throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
        }

        return true;
    }

    /**
     * 出价处理（go出价消费程序调用）
     * @param BiddingMsg $biddingMsg
     * @throws InvalidException
     */
    public function biddingDeal(BiddingMsg $biddingMsg){

        $paramers                   = [];
        $paramers['order_id']      = $biddingMsg->orderId;    //基价
        $paramers['dealer_id']      = $biddingMsg->dealerId;    //基价
        $paramers['org_price']      = $biddingMsg->orgPrice;    //基价
        $paramers['add_price']      = $biddingMsg->addPrice;    //加价
        $paramers['price']          = $biddingMsg->price;       //自定义出价
        $paramers['dev_type']       = $biddingMsg->devType;     //出价设备类型
        $paramers['is_auto']        = $biddingMsg->isAuto;      //是否智能出价
        $paramers['bidding_time']   = $biddingMsg->biddingTime; //出价时间(毫秒)

        $orderId                    = $paramers['order_id'];
        $dealerId                   = $paramers['dealer_id'];

        $orderServ = new OrderService();
        $orderInfo = $orderServ->getOrder($orderId);

        $time = date('Y-m-d H:i:s');

        if($paramers['price']){//自定义出价
            $orgPrice   = $orderInfo['bidding_best_price']>$orderInfo['bid_start_price']?$orderInfo['bidding_best_price']:$orderInfo['bid_start_price'];
            $addPrice   = $paramers['price']-$orgPrice;
            $afterPrice = $paramers['price'];
        }else{
            $orgPrice   = $paramers['org_price'];
            $addPrice   = $paramers['add_price'];
            $afterPrice = $paramers['org_price']+$paramers['add_price'];
        }

        //防止重复调用
        $biddingLogServ = new BiddingLogService();
        $map = [];
        $map['dealer_id'] = $dealerId;
        $map['order_id']  = $orderId;
        $map['after_price']  = $afterPrice;
        $exists = $biddingLogServ->getBiddingLog($map);
        if($exists){
            trace(var_export($exists,true),'','INFO',true);
            trace('GO消费服务重复调用WEAVER忽略。'.var_export($paramers,true),'','INFO',true);
            return true;
        }

        //事务开启
        $orderServ->startTrans();
        try{

            //1,记录竞拍出价记录
            $biddingLogData = array(
                'dealer_id'     => $dealerId,
                'order_id'      => $orderId,
                'before_price'  => $orgPrice,
                'append_price'  => $addPrice,
                'after_price'   => $afterPrice,
                'bidding_time'  => $paramers['bidding_time'],
                'create_mstime' => ms_time(),
                'createtime'    => $time,
                'dev_type'      => $paramers['dev_type'],
                'is_auto'       => $paramers['is_auto'] ? 1 : 0
            );
            $biddingLogService = new BiddingLogService();
            $insertBiddingLogId = $biddingLogService->InsertBiddingLog($biddingLogData);
            if(!$insertBiddingLogId){
                trace("出价日志记录失败：".var_export($biddingLogData,true),'','ERR',true);
                make_throw(360011);
            }

            /*2,***离竞拍结束10秒之内出价，延长30秒竞拍***/
            $diffTimes = time()-strtotime($orderInfo['bidding_start_time']);
            $where = array('order_id'=>$orderId);
            $data  = array('bidding_best_price'=>$afterPrice,'bidding_best_dealer_id'=>$dealerId,'last_time'=>$time);
            if($orderInfo['act_elapsed_time']-$diffTimes <= 10){
                $data['act_elapsed_time'] = $diffTimes+30;
                //修改场内其它顺序单
                if(!$orderInfo['is_timing_order']){
                    $orderServ->resetStartTime($orderInfo);
                }
            }
            $orderServ->setOrderInfo($where,$data);

            //3,清除redis出价记录
            $arr = ['order_id'=>$orderId];
            $keyName = getRedisKeyByCode('REDIS_KEY','100001',$arr);
            $this->redis->del($keyName);

            //4,socket数据类型转换
            $bidding_msg = $this->socketDataConvert($paramers);
            //PUSH 出价信息到 redis,通过node 监听服务广播到各个客户端
            $ok = $this->redis->publish('bidding_msg', json_encode($bidding_msg, true));
            if(!$ok){
                trace('socket广播失败:'.var_export($bidding_msg,true),'','ERR',true);
            }

            //5,更新车商出价的车信息
            $carDealerSrv = new CarDealerService();
            $carDealerSrv->dealerBidPrice($dealerId,$orderId,$afterPrice,'bidding');

            //6,记录车商操作日志
            $dealerLogData      = array(
                'dealer_id'    => $dealerId,
                'order_id'     => $orderId,
                'createtime'   => $time,
                'action'       => '竞标出价,price:'.$afterPrice
            );
            $dealerLogService = new DealerLogService();
            $insertDealerLogId  = $dealerLogService->InsertDealerLog($dealerLogData);
            if(!$insertDealerLogId){
                trace("车商操作日志记录失败：".var_export($dealerLogData,true),'','ERR',true);
            }

            $orderServ->commit();

            //7,智能报价处理
            if($paramers['price']){//自定义出价需要提供基价及加价(兼容)
                $paramers['org_price'] = floatval($orgPrice);
                $paramers['add_price'] = floatval($addPrice);
            }
            $this->dealAutobidding($paramers);

        }catch(\Exception $e){
            trace('捕获异常：'.$e->getMessage(),'','ERR',true);
            $orderServ->rollback();
            return false;
        }
        return true;
    }

    /*
     *  智能出价
     */
    public function intelBidding($dealerId, $orderId,$orgPrice, $addPrice)
    {

        $inPramsBidding = new inParamsBidding();
        $inPramsBidding->dealerId   = intval($dealerId);
        $inPramsBidding->orderId    = intval($orderId);
        $inPramsBidding->basePrice   = floatval($orgPrice);
        $inPramsBidding->addPrice   = floatval($addPrice);
        $inPramsBidding->price      = 0;
        $inPramsBidding->deviceType = 0;
        $inPramsBidding->isAuto     = 1;

        //出价
        $this->bidding($inPramsBidding);

        //出价记录
        $this->insertIntelBidLog($dealerId,$orderId,$orgPrice+$addPrice,1,'');

        return true;
    }

    /**
     * 设置智能出价
     * @param int $dealer_id
     * @param int $order_id
     * @param float $limit_price
     * @return bool
     * @throws InvalidException
     */
    public function intelBidSet($dealer_id, $order_id,$limit_price)
    {

            if(empty($order_id) || $limit_price<=0){
                trace('设置智能出价失败.dealer_id:'.$dealer_id.',order_id:'.$order_id.', limit_price:'.$limit_price,'','ERR',true);
               return false;
            }

            //车商账号判断
            $dealerServ = new CarDealerService();
            $dealer_info = $dealerServ->dealerBaseInfo($dealer_id);
            if(empty($dealer_info)){
                trace('设置智能报价，获取蚁巢车商账号失败','','ERR',true);
                make_throw(360010);
            }
            if($dealer_info['status']!=1){//账号禁用不能设置智能出价
                make_throw(130006);
            }elseif($dealer_info['level']==0){//初级买家不能设置智能出价
                make_throw(360003);
            }

            $orderServ = new OrderService();
            $order_info = $orderServ->getOrder($order_id);

            $bid_start_price = $order_info['bidding_best_price']>$order_info['bid_start_price']?$order_info['bidding_best_price']:$order_info['bid_start_price'];
            if($limit_price<=$bid_start_price){
                make_throw(360009);
            }
            if($limit_price>$order_info['reserve_price']*1.2){
                make_throw(360002);
                throw new InvalidException(array('code' => 360002, 'message' => $this->exceptionCode[360002]));
            }
            if($order_info['status']!=4){
                make_throw(360007);
            }

            //是否已设置过智能报价
            $autoBidding = new AutoBiddingService();
            $last_auto_bidding_info = $autoBidding->getLastAutoBiddingInfo($dealer_id,$order_id);
            if($last_auto_bidding_info['auto_flag'] ==1){
                make_throw(360006);
            }

            $data = array();
            $data['dealer_id'] = $dealer_id;
            $data['order_id'] = $order_id;
            $data['limit_price'] = $limit_price;
            $data['status'] = 1;
            $data['createtime'] = date('Y-m-d H:i:s');

            //db插入数据
            $res = $autoBidding->insertIntelBid($data);

            //redis
            $redis = new PhpRedis();
            $keyName = getRedisKeyByCode('REDIS_KEY','100003');
            $redis->sadd($keyName,$order_id);

            $arr = ['order_id'=>$order_id];
            $keyName = getRedisKeyByCode('REDIS_KEY','100005',$arr);
            $list = $redis->zrange($keyName,0,-1,true);
            $max = $list?max($list):0;

            $keyName = getRedisKeyByCode('REDIS_KEY','100005',$arr);
            $redis->zadd($keyName,$max+1,$dealer_id);

            //车商信息
            $dealerServ = new \ChannelThrift\Service\CarDealerService();
            $dealer_info = $dealerServ->dealerBaseInfo($dealer_id);
            $jpush_id = $dealerServ->getJpushId($dealer_info['uid']);

            $dInfo = array(
                'dealer_id'=>$dealer_id,
                'max_price'=>$limit_price,
                'bid_count'=>1,
                'create_time'=>time(),
                'mobile'=>$dealer_info['pwd_mobile'],
                'jpush_id'=>$jpush_id,
                'is_pushed'=>0
            );
            $arr = ['order_id'=>$order_id,'dealer_id'=>$dealer_id];
            $keyName = getRedisKeyByCode('REDIS_KEY','100006',$arr);
            $redis->set($keyName,json_encode($dInfo));

            return $res?true:false;
    }

    /**
     * 设置智能出价
     * @param int $dealer_id
     * @param int $order_id
     * @return bool
     * @throws InvalidException
     */
    public function intelBidStop($dealer_id, $order_id)
    {

            $autoBidding = new AutoBiddingService();
            //是否有设置记录
            $last_auto_bidding_info = $autoBidding->getLastAutoBiddingInfo($dealer_id,$order_id);
            if(empty($last_auto_bidding_info)){
                make_throw(360005);
            }

            //是否已停止过智能报价
            if($last_auto_bidding_info['status'] ==0){
                make_throw(360008);
            }

            $data = array();
            $data['dealer_id'] = $dealer_id;
            $data['order_id'] = $order_id;
            $data['limit_price'] = $last_auto_bidding_info['limit_price'];
            $data['status'] = 0;
            $data['createtime'] = date('Y-m-d H:i:s');
            $res = $autoBidding->insertIntelBid($data);
            if(!$res){
                return false;
            }

            //redis
            $redis = new PhpRedis();
            $arr = ['order_id'=>$order_id];
            $keyName = getRedisKeyByCode('REDIS_KEY','100005',$arr);
            $redis->zrem($keyName,$dealer_id);

            $arr = ['order_id'=>$order_id,'dealer_id'=>$dealer_id];
            $keyName = getRedisKeyByCode('REDIS_KEY','100006',$arr);
            $redis->del($keyName);

            return true;
    }

    /**
     * 获取最后设置（停止）智能报价信息
     * @param int $dealer_id
     * @param int $order_id
     * @return \Services\AuctionService\LastAutoBiddingInfoMsg
     * @throws InvalidException
     */
    public function getLastAutoSetInfo($dealer_id,$order_id){
            if(empty($dealer_id)){
                make_throw(500001);
            }

            if(empty($order_id)){
                make_throw(700027);
            }
            $autoBiddingServ = new AutoBiddingService();
            $res = $autoBiddingServ->getLastAutoBiddingInfo($dealer_id,$order_id);

            //weaver标准化返回
            $LastAutoBiddingInfoMsg = new \Services\AuctionService\LastAutoBiddingInfoMsg();
            $LastAutoBiddingInfoMsg->dealerId = $dealer_id;
            $LastAutoBiddingInfoMsg->orderId = $order_id;
            $LastAutoBiddingInfoMsg->limitPirce = $res['limit_price'];
            $LastAutoBiddingInfoMsg->status = $res['status'];
            $LastAutoBiddingInfoMsg->createtime = $res['createtime'];
            //
            return $LastAutoBiddingInfoMsg;
    }

    //-----------------------auction service below-------------------------//

    /**
     * 新建/编辑拍卖场
     * @param $objParams
     * @return bool
     * @throws InvalidException
     */
    public function createEditScene(inParamsCreateEditScene $objParams){
            $params = array();
            $params['name']          =  $objParams->name;
            $params['starttime']     =  $objParams->starttime;
            $params['branchId']      =  $objParams->branchId;
            $params['city']          =  $objParams->city;
            $params['sceneActivity'] =  $objParams->sceneActivity;
            $params['sceneId']       =  $objParams->sceneId;
            $params['empId']         =  $objParams->empId;

            //基本数据验证
            if (empty($params['name'])) {
                make_throw(200000);
            }
            if (empty($params['starttime'])) {
                make_throw(200001);
            }
            if (empty($params['branchId'])) {
                make_throw(200002);
            }
            if (empty($params['city'])) {
                make_throw(200003);
            }

            $scene = new SceneService();
            if ($params['sceneActivity']) {
                $starttime = date('Y-m-d H:i:s',$params['starttime']);
                $result = $scene->isActivityAvailable($params['sceneActivity'], $starttime);
                if (!$result) {
                    make_throw(200005);
                }
            }

            $data = array();
            $data['name'] = $params['name'];

            if ($params['starttime']) {
                $data['starttime'] = date("Y-m-d H:i:s",$params['starttime']);
                if ($params['starttime'] < time()) {
                    make_throw(200004);
                }
            }

            $data['branch_id'] = $params['branchId'];
            $data['city'] = $params['city'];
            $data['emp_id'] = $params['empId'];

            if($params['sceneId']){//修改场
                $this->editScene($params,$data);
            }else{//新增场
                $this->addScene($params,$data);
            }

            return true;
    }

    /**
     * 上拍
     * @param $inParams
     * @return bool
     */
    public function createOrder(inParamsCreateOrder $objParams){
        $params = array();
        $params['carId']            =  $objParams->carId;
        $params['sceneId']          =  $objParams->sceneId;
        $params['estElapsedTime']   =  $objParams->estElapsedTime;
        $params['bidStartPrice']    =  $objParams->bidStartPrice;
        $params['transferFee']      =  $objParams->transferFee;
        $params['biddingStartTime'] =  $objParams->biddingStartTime;
        $params['coupon']           =  $objParams->coupon;
        $params['showReservePrice'] =  $objParams->showReservePrice;
        $params['empId']            =  $objParams->empId;

        if(empty($params['carId'])){
            make_throw(300006);
        }
        if(empty($params['sceneId'])){
            make_throw(300007);
        }
        if(empty($params['estElapsedTime'])){
            make_throw(300008);
        }
        if(empty($params['bidStartPrice'])){
            make_throw(300009);
        }
        if(abs($params['bidStartPrice'])%100!=0){
            make_throw(300019);
        }
        if(empty($params['transferFee'])){
            make_throw(300010);
        }

        $car = new CarService();
        $carInfo = $car->getCar($params['carId']);

        $scene = new SceneService();
        $map = array('scene_id'=>array('eq',$params['sceneId']));
        $sceneDetail = $scene->getSceneInfo($map);
        //判断场次所属城市是否与车辆所在地相符
        if ($sceneDetail['city'] != $carInfo['location_area']) {
            make_throw(300000);
        }
        if ($sceneDetail['status'] == 3) {
            make_throw(300011);
        }

        $order = new OrderService();
        //如果是定时单需要判断指定的开拍时间是否合法

        if ($params['biddingStartTime']) {
            $ret = $order->checkBiddingStartTime($params['sceneId'], $params['biddingStartTime']);
            if (!$ret) {
                make_throw(300001);
            }
        }

        //数据
        $data = array();
        //$data['emp_id'] = $this->emp_id;//新上拍这个字段为0，客服点点确认后
        //表单数据
        $data['car_id']                 = $params['carId']; //车源ID
        $data['scene_id']               = $params['sceneId']; //场次ID
        $data['est_elapsed_time']       = $params['estElapsedTime']; //预计耗时(秒）
        if ($params['biddingStartTime']) {
            $biddingStartTime = date('Y-m-d H:i:0',$params['biddingStartTime']);
            $data['bidding_start_time'] = $biddingStartTime; //开拍时间
            $data['is_timing_order']    = '1'; //定时单
        } else {
            $data['bidding_start_time'] = $order->getBiddingStartTime($params['sceneId']); //算出开拍时间
            $data['is_timing_order']    = '0'; //顺序单
        }
        $data['bid_start_price']        = $params['bidStartPrice']; //起拍价
        $data['coupon']                 = $params['coupon']; //可用代金券额度
        $data['transfer_fee']           = $params['transferFee']; //过户费
        $data['commision']              = get_commision($params['bidStartPrice'], $sceneDetail['starttime']); //交易服务费
        $data['reserve_price']          = $carInfo['reserve_price'];
        $data['status']                 = '1'; //1 审核中
        $data['show_reserve_price']     = $params['showReservePrice'];
        $data['emp_id']                 = $params['empId'];

        $orderId = 0;//define
        try {
            $orderId = $order->createOrder($data);
            if (!$orderId) {
                make_throw(300002);
            }
        } catch (InvalidException $e) {
            throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
        }

        //更新车源拍单ID
        $CarSource = new CarSourceService();
        $CarSourceInfo = $CarSource->getInfo($carInfo['sid']);
        if ($CarSourceInfo['status'] == 100) {
            $csData = [];
            $csData['order_id'] = $orderId;
            $resCs = $CarSource->update($carInfo['sid'],$csData);
            if($resCs === false){
                make_throw(300017);
            }
        }

        //记录车辆跟踪日志
        $carActionData = array(
            'action_name' => '开始上拍',
            'emp_id' => $params['empId']
        );
        CarService::addCarTraceLog($params['carId'], $carActionData);

        //记录拍品跟踪日志 -- 开始
        $orderActionData = array(
            'action_name' => '开始上拍',
            'emp_id' => $params['empId']
        );
        OrderService::addOrderTraceLog($orderId, $orderActionData);

        return true;
    }

    /**
     * 上拍审核
     * @param int $orderId  拍单ID
     * @param bool $result  处理结果（true 通过 false 驳回）
     * @param string $remark    驳回原因
     * @param int $empId        操作者
     * @return bool
     */
    public function auditOrder($orderId,$result,$remark='',$empId=0){
            if(empty($orderId)){
                make_throw(300015);
            }
            if(!$result && $remark==''){
                make_throw(300016);
            }
            //获取拍单信息
            $order = new OrderService();
            $detail = $order->getOrder($orderId);

            //更新车源上拍次数,流拍次数
            $cars = new CarService();
            $carDetail = $cars->getCar($detail['car_id']);

            $return = true;
            if ($result) {//审核通过
                //数据验证
                if ($detail['status'] > 3) {
                    make_throw(300013);
                }

                //时效性验证(暂不支持场开始后追加拍单）
                $scene = new SceneService();
                $map = ['scene_id'=>$detail['scene_id']];
                $scene = $scene->getSceneInfo($map);
                if ($scene['status'] == 3) {
                    make_throw(300011);
                }

                //时效性验证
                if ($scene['status'] == 2) {
                    make_throw(300020);
                }

                //要提前场开始时间2分钟审核
                if ((time() + 120) > strtotime($scene['starttime'])) {
                    make_throw(300021);
                }

                //审核通过
                $this->auditPass($detail,$carDetail);

                //来拍车订阅推送
                $antServ = new AntNestService();
                $antServ->subscribe($empId,$orderId);

                //增加智能出价redis key
                $this->auditRedis($detail,$carDetail);

                $msg = '上拍审核成功';
            } else{//审核驳回
                //判断重复驳回
                if ($detail['status'] == 2) {
                    make_throw(300014);
                }
                //判断是否在审核中
                if ($detail['status'] != 1) {
                    make_throw(300018);
                }

                //开启事务
                $order->startTrans();
                $res1 = $order->resetOrderRank($detail);
                $res2 = $order->resetOrderStartTime($detail);
                //更新拍单表
                $data = array();
                $data['status'] = '2'; //审核驳回
                $data['rank'] = '0'; //排序置0
                $data['remark_reject'] = $remark;
                $res = $order->update($orderId,$data);
                if ($res && $res1 && $res2) {
                    $order->commit();//提交事务
                    $msg = '驳回上拍成功';
                } else {
                    $order->rollback();//事务回滚
                    $msg = '驳回上拍失败';
                    $return = false;
                }
            }

            //记录相关日志
            $logParams = [];
            $logParams['order_id']  = $orderId;
            $logParams['car_id']    = $detail['car_id'];
            $logParams['msg']       = $msg;
            $logParams['emp_id']    = $empId;
            $logParams['status']    = $detail['status'];
            $this->recordLog($logParams);

            return $return;
    }

    /**
     * 钟点触发开场服务（支持开场后追加拍单）
     * @param int $time unix时间戳
     * @return bool
     */
    public function startTrigger($time){
        $return = [];
        $time = date('Y-m-d H:i:0',$time);

        $orderObj = new OrderService();
        //把开场时间等于$time的场找出来场开始
        $sceneObj = new SceneService();
        $map = [];
        $map['status'] = ['eq',1];
        $map['starttime'] = ['eq',$time];
        $scenes = $sceneObj->getScenes($map);
        if($scenes){
            foreach($scenes as $scene){
                $map = [];
                $map['scene_id'] = ['eq',$scene['scene_id']];
                $map['status'] = ['eq',3];
                $os = $orderObj->getOrders($map);
                if(count($os)==0){
                    trace('场'.$scene['scene_id'].'不能开始，场内无拍单','','ERR',true);
                    continue;
                }
                $arr=[];
                foreach($os as $o){
                    $arr[]=$o['order_id'];
                }
                //场开始
                trace('场('.$scene['scene_id'].')开始','','INFO',true);
                $this->startScene($scene['scene_id']);
                trace('场('.$scene['scene_id'].')内拍单：'.implode(',',$arr),'','INFO',true);
                //场内所有拍单置为待竞拍
                $this->orderWaitBidding($scene['scene_id']);
            }
        }

        //拍单开始
        $map = [];
        $map['status'] = ['eq',301];
        $map['bidding_start_time'] = ['eq',$time];
        $orders = $orderObj->getOrders($map);
        if($orders){
            foreach($orders as $orderInfo){
                if(!$orderInfo['is_timing_order']){
                    //顺序单只开始第一个，其它的由结束程序开始
                    //第一个顺序单rank可能不是1，故需要找出该场内第一个顺序单
                    $isFirstSeqOrder = $orderObj->isFirstSeqOrder($orderInfo);
                    if(!$isFirstSeqOrder){
                        trace($orderInfo['order_id'].'不是第一个有效顺序单，忽略','','INFO',true);
                        continue;
                    }
                }
                trace(($orderInfo['is_timing_order']?'定时':'顺序').'拍单('.$orderInfo['order_id'].')开始竞拍','','INFO',true);
                try{
                    $this->startBidding($orderInfo);
                }catch(\Exception $e){
                    throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
                }

                $orderSceneObj = new OrderSceneMsg();
                $orderSceneObj->orderId             = intval($orderInfo['order_id']);
                $orderSceneObj->biddingStartTime    = strtotime($orderInfo['bidding_start_time']);
                $orderSceneObj->estElapsedTime      = intval($orderInfo['est_elapsed_time']);
                $orderSceneObj->actElapsedTime      = intval($orderInfo['act_elpsed_time']);
                $orderSceneObj->isTimingOrder      = intval($orderInfo['is_timing_order']);
                $orderSceneObj->sceneId             = intval($orderInfo['scene_id']);
                $sceneObj = new SceneService();
                $map=['scene_id'=>['eq',$orderInfo['scene_id']]];
                $sceneInfo = $sceneObj->getSceneInfo($map);
                $orderSceneObj->sceneStartTime      = strtotime($sceneInfo['starttime']);
                $return[$orderSceneObj->orderId]    = $orderSceneObj;
            }
        }
        return $return;
    }

    /**
     * 钟点触发结束场服务
     * @param int $orderId
     * @param bool $isForce
     * @return OrderSceneMsg
     */
    public function endTrigger($orderId,$isForce=false)
    {
        $order = new OrderService();
        $orderInfo = $order->getOrder($orderId);
        if($orderInfo['status']>=5){
            make_throw(400014,'',[$orderId]);
        }
        if($isForce){
            trace(($orderInfo['is_timing_order']?'定时':'顺序').'拍单('.$orderInfo['order_id'].')强制结束竞拍','','INFO',true);
            try{
                $this->endBidding($orderId);
            }catch(\Exception $e){
                throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
            }

            return $this->returnStdEndTrigger($orderInfo);
        }
        //结束顺序单，先判断上一个顺序单是否已结束，若未结束不能结束当前顺序单，返回上一个顺序单信息
        //结束当前顺序单，并把顺序单信息返回给钟点服务，同时开始下一个顺序单
        $isFirstSeqOrder = $order->isFirstSeqOrder($orderInfo);
        if(!$orderInfo['is_timing_order'] && !$isFirstSeqOrder){
            //判断上一个顺序单
            $map = [];
            $map['is_timing_order'] = ['eq',0];
            $map['rank'] = ['lt',$orderInfo['rank']];
            $preSeqOrderInfo = $order->getOrderByMap($map,'rank DESC');
            if($preSeqOrderInfo['status']!=5){//上一个顺序单未结束，返回上一个顺序单信息给钟点服务
                return $this->returnStdEndTrigger($preSeqOrderInfo);
            }
        }

        //判断结束时间
        $t1 = strtotime($orderInfo['bidding_start_time'])+$orderInfo['est_elapsed_time'];//预计结束时间
        $t2 = strtotime($orderInfo['bidding_start_time'])+$orderInfo['act_elapsed_time'];//实际结束时间
        if(time()>=$t1 && $orderInfo['act_elapsed_time']==0){
            //预计结束时间时调用(第一次调用）
            if($orderInfo['act_elapsed_time']>$orderInfo['est_elapsed_time']){
                //结构化返回最新act_elapsed_time
                return $this->returnStdEndTrigger($orderInfo);
            }

            //结束预计拍单
            trace(($orderInfo['is_timing_order']?'定时':'顺序').'拍单('.$orderInfo['order_id'].')结束竞拍','','INFO',true);
            try{
                $this->endBidding($orderId);
            }catch(\Exception $e){
                throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
            }

            if(!$orderInfo['is_timing_order']){
                //开始下一个顺序单
                $map = [];
                $map['scene_id'] = ['eq',$orderInfo['scene_id']];
                $map['is_timing_order'] = ['eq',0];
                $map['rank'] = ['gt',$orderInfo['rank']];
                $nextSeqOrderInfo = $order->getOrderByMap($map,'rank ASC');
                if($nextSeqOrderInfo){
                    trace('[endTrigger]顺序单('.$nextSeqOrderInfo['order_id'].')开始竞拍','','INFO',true);
                    try{
                        $this->startBidding($nextSeqOrderInfo);
                    }catch(\Exception $e){
                        throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
                    }

                    //返回下一个顺序单信息给钟点服务，服务需要知道该单预计结束时间
                    return $this->returnStdEndTrigger($nextSeqOrderInfo);
                }
            }
        }elseif(time()>=$t2){
            //结束延时拍单（第二次调用）
            trace(($orderInfo['is_timing_order']?'定时':'顺序').'拍单('.$orderId.')结束竞拍','','INFO',true);

            try{
                $this->endBidding($orderId);
            }catch(\Exception $e){
                throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
            }

            //开始下一个顺序单，并返回下一个顺序单信息给钟点服务
            if(!$orderInfo['is_timing_order']){
                //开始下一个顺序单
                $map = [];
                $map['scene_id'] = ['eq',$orderInfo['scene_id']];
                $map['is_timing_order'] = ['eq',0];
                $map['rank'] = ['gt',$orderInfo['rank']];
                $nextSeqOrderInfo = $order->getOrderByMap($map,'rank ASC');
                if($nextSeqOrderInfo) {
                    trace('[前单或网络延时]顺序单(' . $nextSeqOrderInfo['order_id'] . ')开始竞拍', '', 'INFO', true);
                    try{
                        $this->startBidding($nextSeqOrderInfo);
                    }catch(\Exception $e){
                        throw new InvalidException(array('code' => $e->getCode(), 'message' => $e->getMessage()));
                    }

                    //返回下一个顺序单信息给钟点服务，服务需要知道该单预计结束时间
                    return $this->returnStdEndTrigger($nextSeqOrderInfo);
                }
            }
        }else{
            //结构化返回最新act_elapsed_time
            return $this->returnStdEndTrigger($orderInfo);
        }

        //判断并-结束场
        $map = [];
        $map['scene_id'] = $orderInfo['scene_id'];
        $map['status'] = ['in','3,301,4'];
        $orders = $order->getOrders($map);
        if(empty($orders)){
            trace('场('.$orderInfo['scene_id'].')结束','','INFO',true);
            $this->endScene($orderInfo['scene_id']);
        }

        return $this->returnStdEndTrigger($orderInfo);
    }

    //----------------private function below-----------------------------------//

    private function returnStdEndTrigger($orderInfo){
        $return = [];
        //结构化返回
        $orderSceneObj                      =   new OrderSceneMsg();
        $orderSceneObj->orderId             =   $orderInfo['order_id'];
        $orderSceneObj->biddingStartTime    =   strtotime($orderInfo['bidding_start_time']);
        $orderSceneObj->estElapsedTime      =   intval($orderInfo['est_elapsed_time']);
        $orderSceneObj->actElapsedTime      =   intval($orderInfo['act_elapsed_time']);
        $orderSceneObj->isTimingOrder       =   intval($orderInfo['is_timing_order']);
        $orderSceneObj->sceneId             =   intval($orderInfo['scene_id']);

        $sceneObj = new SceneService();
        $map=['scene_id'=>['eq',$orderInfo['scene_id']]];
        $sceneInfo = $sceneObj->getSceneInfo($map);
        $orderSceneObj->sceneStartTime      =   strtotime($sceneInfo['starttime']);

        $return[$orderInfo['order_id']] = $orderSceneObj;
        return $return;
    }
    /**
     * 场内所有拍单置为待竞拍
     * @param $sceneId
     */
    private function orderWaitBidding($sceneId)
    {
        $orderObj = new OrderService();
        $data = ['status'=>301];
        $rs = $orderObj->updateBySceneId($sceneId,$data);
        if($rs === false){
            make_throw(400002,'',[$sceneId]);
        }
    }

    /**
     * 场开始
     * @param $sceneId
     */
    private function startScene($sceneId){
        $scene = new SceneService();
        $map = ['scene_id'=>['eq',$sceneId]];
        $data = ['status'=>2];
        $rs = $scene->editScene($map,$data);
        if($rs === false){
            make_throw(400000,'',[$sceneId]);
        }
    }

    /**
     * 场结束
     * @param $sceneId
     */
    private function endScene($sceneId){
        $scene = new SceneService();
        $map = ['scene_id'=>['eq',$sceneId]];
        $data = ['status'=>3,'endtime'=>date('Y-m-d H:i:s')];
        $rs = $scene->editScene($map,$data);
        if($rs === false){
            make_throw(400001,'',[$sceneId]);
        }
    }

    /**
     * 开始竞拍
     * @param $orderInfo
     * @throws \Services\BailService\InvalidException
     */
    private function startBidding($orderInfo){

        //获取最高投标价及最高投标车商
        $m = D('ChannelThrift/Aums/DealerBid');
        $map = ['order_id'=>['eq',$orderInfo['order_id']]];
        $res = $m->where($map)->field("last_bid_price price,dealer_id")->order('last_bid_price DESC')->find();

        //开启事务
        $m->startTrans();
        //更新拍单状态为竞拍中
        $order = new OrderService();
        $data = [];
        $data['bid_best_price'] = $res['price'];
        $data['bid_best_dealer_id'] = $res['dealer_id'];
        //$data['bidding_start_time'] = date('Y-m-d H:i:s');上拍时已定好开拍时间，不必再修改一次
        $data['status'] = 4;
        $rs = $order->update($orderInfo['order_id'],$data);
        if($rs === false){
            $m->rollback();
            make_throw(400003,'',[$orderInfo['order_id']]);
        }
        if ($res['dealer_id']) {
            //查询除中标车商外 所有投标车商ID
            $dblService = new DealerBailLogService();
            $dealers = $dblService->getUnFreeDealers($orderInfo['order_id'],$res['dealer_id']);

            if($dealers){

                $newArr = array();
                foreach($dealers as $key=>$val){
                    $newArr[] = $val['dealer_id'];
                }

                trace('即时解冻其他车商保证金:' . implode(',',$newArr), '', 'INFO', true);

                if(!empty($newArr)){
                    $bailService = new BailService();
                    try{
                        $result = $bailService->unfreezeBail(implode(',',$newArr),$orderInfo['order_id']);
                        if($result->code!='000000'){
                            $m->rollback();
                            make_throw(400004,'',[$orderInfo['order_id'],implode(',',$newArr),$result->message]);
                        }
                    }catch(\Exception $e){
                        make_throw($e->getCode(),'',[$orderInfo['order_id'],implode(',',$newArr),$e->getMessage()]);
                    }
                }
            }

        }else{
            trace(($orderInfo['is_timing_order']?'定时':'顺序').'拍单('.$orderInfo['order_id'].')无人投标!','','INFO',true);
        }

        //更新拍单进度状态
        $now = microtime_time();
        $data = [];
        $data['order_id'] = $orderInfo['order_id'];
        $data['car_id']   = $orderInfo['car_id'];
        $data['emp_name'] = '--';
        $data['action_no'] = 1007;
        $data['action_name'] = '开始竞拍';
        $data['createtime'] = $now;
        $rs = OrderService::addOrderTraceLog($orderInfo['order_id'],$data);
       if(!$rs){
           $m->rollback();
           make_throw(400005,'',[$orderInfo['order_id']]);
        }
        $carObj = new CarService();
        $carInfo = $carObj->getCar($orderInfo['car_id']);

        $data = [];
        $data['owner_id'] = $carInfo['owner_id'];
        $data['car_id'] = $orderInfo['car_id'];
        $data['emp_name'] = '--';
        $data['action_no'] = 1013;
        $data['action_name'] = '开始竞拍';
        $data['createtime'] = $now;
        $rs = CarService::addCarTraceLog($orderInfo['car_id'],$data);
        if(!$rs){
            $m->rollback();
            make_throw(400006,'',[$orderInfo['order_id']]);
        }
        //提交事务
        $m->commit();
    }

    /**
     * 结束竞拍
     * @param $orderId
     * @param bool $isForce 是否强制结束
     * @return bool
     */
    private function endBidding($orderId){

        $redis = new PhpRedis();
        //获取拍卖结束锁
        $arr = ['order_id'=>$orderId];
        $lock_key = getRedisKeyByCode('REDIS_KEY','100025',$arr);
        $r = $redis->lock_wait($lock_key,60);

        if(!$r){
            make_throw(400013,'',[$orderId]);
        }

        try{
            //获取拍单详情
            $orderService = new OrderService();
            $orderInfo = $orderService->getOrder($orderId);

            if($orderInfo['status'] != 4){
                make_throw(400008,'',[$orderId]);
            }

            //开启事务
            $orderService->startTrans();

            //1,更新拍单状态为待确认
            $time = date('Y-m-d H:i:s',time());
            $data = [];
            $data['status']             = 5;
            $data['last_time']          = $time;
            $data['bidding_end_time']   = $time;
            $rs = $orderService->update($orderInfo['order_id'],$data);
            if($rs === false){
                $orderService->rollback();
                make_throw(400009,'',[$orderId]);
            }

            //2,更新车源状态为待确认
            $car = new CarService();
            $carInfo = $car->getCar($orderInfo['car_id']);
            $carSource = new CarSourceService();
            $carSourceInfo = $carSource->getInfo($carInfo['sid']);
            if($carSourceInfo['status']==200){
                $data = ['status'=>300];
                $rs = $carSource->update($carInfo['sid'],$data);
                if($rs === false){
                    $orderService->rollback();
                    make_throw(400010,'',[$orderId]);
                }
            }

            //3,记录交易服务费
            $rs = $this->updateCommision($orderInfo);
            if(!$rs){
                $orderService->rollback();
                make_throw(400011,'',[$orderId]);
            }

            $success_dealer_id = $orderInfo['bidding_best_price']>=$orderInfo['bid_best_price']?$orderInfo['bidding_best_dealer_id']:$orderInfo['bid_best_dealer_id'];
            //4,解冻未中标车商保证金 即时解冻其他车商保证金(从投标到竞拍结束全程只冻结一名出价最高的车商保证金)
            if($success_dealer_id) {
                $dblService = new DealerBailLogService();
                $dealers = $dblService->getUnFreeDealers($orderId, $success_dealer_id);

                if ($dealers) {
                    trace('即时解冻其他车商保证金:' . var_export($dealers, true), '', 'INFO', true);
                    $newArr = array();
                    foreach ($dealers as $key => $val) {
                        $newArr[] = $val['dealer_id'];
                    }
                    //empty($dealers)一人出价
                    if (!empty($newArr)) {//多人出价
                        $bailService = new BailService();
                        try{
                            $result = $bailService->unfreezeBail(implode(',', $newArr), $orderInfo['order_id']);
                            if ($result->code != '000000') {
                                make_throw(400012, '', [$orderId, $result->message]);
                            }
                        }catch(\Exception $e){
                            make_throw($e->getCode(), $e->getMessage());
                        }
                    }
                }
            }else{
                trace($orderId.'无人出价','','INFO',true);
            }
            //5,记录拍单跟踪日志
            $now = microtime_time();//毫秒

            $data=[];
            $data['order_id'] = $orderId;
            $data['car_id']   = $orderInfo['car_id'];
            $data['emp_name'] = '--';
            $data['action_no'] = 1008;
            $data['action_name'] = '竞拍结束';
            $data['createtime'] = $now;
            $rs = OrderService::addOrderTraceLog($orderInfo['order_id'],$data);
            if($rs === false){
                $orderService->rollback();
                make_throw(400005,'',[$orderId]);
            }

            //6,记录车辆跟踪日志
            $data = [];
            $data['owner_id']       =   $carInfo['owner_id'];
            $data['car_id']         =   $orderInfo['car_id'];
            $data['emp_name']       =   '--';
            $data['action_no']      =   1014;
            $data['action_name']    =   '竞拍结束';
            $data['createtime']     =   $now;
            $rs = CarService::addCarTraceLog($orderInfo['car_id'],$data);
            if($rs === false){
                $orderService->rollback();
                make_throw(400006,'',[$orderId]);
            }

            //7,处理违约重拍 -- 到平台确认
            if ($carInfo['is_dealer_breach'] == 1) {
                $rs = $orderService->breachRedoPlatform($orderId);
                if($rs === false){
                    $orderService->rollback();
                    make_throw(400015,'',[$orderId]);
                }
            }

            //8,处理自收重拍
            $rs = $orderService->selfReceiveRedo($orderId,$success_dealer_id);
            if($rs === false){
                $orderService->rollback();
                make_throw(400016,'',[$orderId]);
            }
            //提交事务
            $orderService->commit();

            //删除结束锁
            $redis->unlock($lock_key);

            //9,删除智能出价相关redis 队列
            $arr = ['order_id'=>$orderId];
            $keyName = getRedisKeyByCode('REDIS_KEY','100003',$arr);
            $redis->srem($keyName,$orderId);

            $keyName = getRedisKeyByCode('REDIS_KEY','100005',$arr);
            $redis->del($keyName);//删除所有设置智能出价的车商

            //scan方式删除所有设置智能出价的车商信息key
            $keyName = getRedisKeyByCode('REDIS_KEY','100012',$arr);
            $it = NULL;//初始化游标
            while($arr_keys = $redis->scan($it,$keyName,1000)) {
                foreach($arr_keys as $str_key) {
                    trace('[scan]删除redis Key:'.$str_key,'','INFO',true);
                    $redis->del($str_key);
                }
                break;
            }

            $keyName = getRedisKeyByCode('REDIS_KEY','100004',$arr);
            $redis->del($keyName);

            $keyName = getRedisKeyByCode('REDIS_KEY','100007',$arr);
            $redis->del($keyName);

        }catch (\Exception $e){
            //删除结束锁
            $redis->unlock($lock_key);
            make_throw($e->getCode(),$e->getMessage());
        }

    }

    private function updateCommision($orderInfo){
            if($orderInfo['bidding_best_price'] > $orderInfo['bid_best_price']){
                $bestPrice = $orderInfo['bidding_best_price'];
                $successDealerId = $orderInfo['bidding_best_dealer_id'];
            }else{
                $bestPrice = $orderInfo['bid_best_price'];
                $successDealerId = $orderInfo['bid_best_dealer_id'];
            }
            $commision = get_commision($bestPrice);
            $orderServie = new OrderService();
            $data = [];
            $data['success_price'] = $bestPrice;
            $data['success_dealer_id'] = $successDealerId;
            $data['commision'] = $commision;
            $rs = $orderServie->update($orderInfo['order_id'],$data);
            if($rs === false){
                return false;
            }
            return true;
    }

    /**
     * 审核通过
     * @param $orderDetail
     * @param $carDetail
     * @throws InvalidException
     */
    private function auditPass($orderDetail,$carDetail){
        $order = new OrderService();
        //开启事务
        $order->startTrans();

        //更新车源状态
        $CarSource = new CarSourceService();
        $CarSourceInfo = $CarSource->getInfo($carDetail['sid']);
        $resCs = true;//define
        if ($CarSourceInfo['status'] == 100) {
            $csData = ['status'=>200];
            $resCs = $CarSource->update($carDetail['sid'],$csData);
        }

        $carData = array();
        $carData['car_status']  = '5';
        $carData['au_times']    = $carDetail['au_times'] + 1;
        if ($orderDetail['status'] == '6' && $carDetail['re_auction_type'] == '1') {
            $carData['unsold_times'] = $carDetail['unsold_times'] - 1;
        }
        $cars = new CarService();
        $res1 = $cars->update($orderDetail['car_id'],$carData);

        //更新拍单表
        $data = array();
        $data['status'] = '3'; //审核通过，状态改为3 拍卖中
        $data['bid_start_time'] = date('Y-m-d H:i:s');//原来的投标开始时间，现在为审核通过时间
        $res = $order->update($orderDetail['order_id'],$data);

        if ($res===false || $res1===false || $resCs===false) {
            M()->rollback();
            make_throw(300012);
        }
        $order->commit();

    }

    //智能出价redis更新
    private function auditRedis($orderDetail,$carDetail){
        //所在地
        $a = new AddressService();
        $city_name = $a->get_name_by_code($carDetail['location_area']);

        //车系
        $cm = new CarModelService();
        $series = $cm->get_model_by_id($carDetail['series_id'], 'series');
        //合成车型
        $carModel = '[' . $city_name . '] ' . $series['name'] . ' ' . $carDetail['car_cc'] . ($carDetail['turbo'] ? 'T' : 'L') . ' ' . C('GEARBOX.' . $carDetail['gearbox']);


        $redis = new PhpRedis();
        $orderInfo = array(
            'order_id' => intval($orderDetail['order_id']),
            'bidding_start_time' => $orderDetail['bidding_start_time'],
            'bid_start_price' => floatval($orderDetail['bid_start_price']),
            'order_no' => $orderDetail['order_no'],
            'car_model' => $carModel
        );
        $arr = [
            'order_id'=>$orderDetail['order_id'],
        ];
        $keyName = getRedisKeyByCode('REDIS_KEY','100004',$arr);
        $redis->set($keyName, json_encode($orderInfo));
    }


    /**
     * 记录相关日志
     * @param $params
     */
    private function recordLog($params){
        $orderId = $params['order_id'];
        $carId  =   $params['car_id'];
        $empId  = $params['emp_id'];
        $msg    = $params['msg'];
        $status    = $params['status'];

        //记录操作日志
        $log = array('emp_id' => $empId, 'order_id' => $orderId, 'action' => $msg);
        SystemLogService::addlog($log);

        //记录车辆跟踪日志
        $carActionData = array(
            'action_name' => $msg,
            'emp_id' => $empId
        );
        CarService::addCarTraceLog($carId, $carActionData);

        //记录拍品跟踪日志
        $orderActionData = array(
            'action_name' => $msg,
            'emp_id' => $empId
        );
        OrderService::addOrderTraceLog($orderId, $orderActionData);

        if ($status == 3) {
            /**
             * 上拍审核成功->即竞标开始
             * 记录车辆跟踪日志
             */
            $carActionData = array(
                'action_name' => '开始投标',
                'emp_id' => 0
            );
            CarService::addCarTraceLog($carId, $carActionData);
            /**
             * 记录拍品跟踪日志
             */
            $orderActionData = array(
                'action_name' => '开始投标',
                'emp_id' => 0
            );
            OrderService::addOrderTraceLog($orderId, $orderActionData);
        }

    }
    /**
     * 新增出价记录
     * @param $dealer_id
     * @param $order_id
     * @param $price
     * @param $result
     * @param $remark
     * @return bool|mixed
     */
    private function insertIntelBidLog($dealer_id,$order_id,$price,$result=1,$remark=''){
        $autoBiddingLog = new AutoBiddingLogService();
        $autoBidding = new AutoBiddingService();
        $autoBiddingInfo = $autoBidding->getLastAutoBiddingInfo($dealer_id,$order_id);
        $data = array();
        $data['ab_id'] = $autoBiddingInfo['ab_id']?$autoBiddingInfo['ab_id']:11;
        $data['dealer_id'] = $dealer_id;
        $data['order_id'] = $order_id;
        $data['price'] = $price;
        $data['result'] = $result;
        $data['remark'] = $remark;
        $res = $autoBiddingLog->insertIntelBidLog($data);
        return $res;
    }

    /**
     * jpush 推送消息
     * @param $dealer_id
     * @param $order_id
     * @param $next_price
     */
    private function jpushMsg($redis,$dealer_id,$order_id,$next_price,$antServ){
        $arr = ['order_id'=>$order_id,'dealer_id'=>$dealer_id];
        $keyName = getRedisKeyByCode('REDIS_KEY','100006',$arr);
        $dealer_info = json_decode($redis->get($keyName),true);

        $arr = ['order_id'=>$order_id];
        $keyName = getRedisKeyByCode('REDIS_KEY','100004',$arr);
        $order_info = json_decode($redis->get($keyName),true);
        //推送信息
        $jpush_data = array('order_id'=>$order_id);
        $jpush_content = '【智能报价】'.$order_info['car_model'].'，拍单编号：'.$order_info['order_no'].'，当前价'.format_money($next_price).'元，即将超过您设置的智能报价上限。 ';
        $res = $antServ->jpush_msg($dealer_info['mobile'],$dealer_info['jpush_id'],2,$jpush_data,$jpush_content);
        return $res;
    }

    private function addScene($params,$data){
        $scene = new SceneService();
        $scene->startTrans();
        $res = $scene->addScene($data);
        if ($params['sceneActivity']) {
            $activityArr = [
                'scene_id' => $res,
                'scene_activity_id' => $params['sceneActivity'],
                'emp_id' => $params['empId'],
                'createtime' => date('Y-m-d H:i:s', time()),
            ];
            $result = $scene->addOrEditeSceneActivity($activityArr);
            if ($res === false || $result === false) {
                M()->rollback();
                $code = 200007;
                $msg = $this->exceptionCode[$code];
                trace($msg,'','ERR',true);
                throw new InvalidException(array('code' => $code, 'message' => $msg));
            }
        }
        $scene->commit();
    }

    private function editScene($params,$data){
        $scene = new SceneService();
        //判断场状态（只能修改未开场的场信息）
        $map = array();
        $map['scene_id'] = array('eq',$params['sceneId']);
        $sceneInfo = $scene->getSceneInfo($map);
        if($sceneInfo['status']!='1'){
            $code =  200009;
            $msg = $this->exceptionCode[$code];
            trace($msg,'','ERR',true);
            throw new InvalidException(array('code' => $code, 'message' => $msg));
        }

        //检查场次开始时间是否在定时单前面
        $ret = $scene->checkStarttime($params['sceneId'], $params['starttime']);
        if (!$ret) {
            $code =  200006;
            $msg = $this->exceptionCode[$code];
            trace($msg,'','ERR',true);
            throw new InvalidException(array('code' => $code, 'message' => $msg));
        }

        //开启事务
        $scene->startTrans();

        //场信息修改
        $map = array();
        $map['scene_id'] = array('eq',$params['sceneId']);
        $res = $scene->editScene($map,$data);

        //重新计算场次内非定时单的开拍时间
        $res1 = $scene->ReComputeStarttime($params['sceneId']);

        //场活动处理
        if ($params['sceneActivity']) { //如果选了活动
            $activityArr = [
                'scene_id' => $params['sceneId'],
                'scene_activity_id' => $params['sceneActivity'],
                'emp_id' => $params['empId'],
                'createtime' => date('Y-m-d H:i:s', time()),
            ];
            $res2 = $scene->addOrEditeSceneActivity($activityArr);
            if (!$res2) {
                M()->rollback();
                $code = 200010;
                $msg = $this->exceptionCode[$code];
                trace($msg,'','ERR',true);
                throw new InvalidException(array('code' => $code, 'message' => $msg));
            }
        } else {
            $activityArr = [
                'scene_id' => $params['sceneId'],
            ];
            $res2 = $scene->deleteSceneActivity($activityArr);
        }

        if ($res !== false && $res1 && $res2) {
            $scene->commit();
        } else {
            $scene->rollback();
            $code = 200008;
            $msg = $this->exceptionCode[$code];
            trace($msg,'','ERR',true);
            throw new InvalidException(array('code' => $code, 'message' => $msg));
        }

    }

    /**
     * 出价条件检查
     * @param $paramers
     * @return array
     * @throws InvalidException
     */
    private function preCheck($paramers){
        global $origin_price_lock_key,$bidding_end_lock_key,$ulock_key,$ulock_key1;
        $order_id   = $paramers['order_id'];
        $dealer_id  = $paramers['dealer_id'];
        $org_price  = $paramers['org_price'];
        $add_price  = $paramers['add_price'];
        $price      = $paramers['price'];//自定义出价
        $dev_type   = $paramers['dev_type'];
        $is_auto    = $paramers['is_auto'];
        $isCus      = ($org_price==0 && $add_price==0) ? true : false;
        //竞拍结束锁
        if($this->redis->exists($bidding_end_lock_key)){
            //拍单正在结束，不能出价。
            make_throw(700045);
        }

        //------------防止1秒内连续出价
        if(!$this->redis->lock($ulock_key)){
            //发生异常，抛出异常提示
            make_throw(700044);
        }
        if($this->redis->exists($ulock_key1)){
            $this->redis->unlock($ulock_key);
            //发生异常，抛出异常提示
            make_throw(700044);
        }
        $this->redis->set($ulock_key1,$dealer_id,1);
        $this->redis->unlock($ulock_key);

        //----------拍单锁（基价锁）加锁
        if(!$this->redis->lock($origin_price_lock_key)){
            trace('dealer_id:'.$dealer_id.' order_id:'.$order_id.' 基价锁加锁失败。origin_price_lock_key:'.$origin_price_lock_key,'','ERR',true);
            make_throw(700008);
        }

        //获取最低保证金配置值
        $sysConfServ = new SystemConfService();
        $bail_info = $sysConfServ->getConfByName('BAIL');
        $freeze_price  = $bail_info['value'];

        //-------------
        $orderServ = new OrderService();
        $order_info = $orderServ->getOrder($order_id);//拍单基本信息，发生并发处，前置需要加锁

        $db_org_price = $order_info['bidding_best_price'];  //库里基础价
        $start_price = $order_info['bid_start_price'];//起拍价
        if ($db_org_price == 0) {
            $db_org_price = $start_price;
        }

        if($isCus){//自定义出价
            if(empty($price)){
                make_throw(700049);
            }elseif(strlen(abs($price)) > 7){
                make_throw(700051);
            }elseif($price%100!=0){
                make_throw(700050);
            }
            //自定义出价与当前最高价的差价
            $diff_price = $price-$db_org_price;
            if($diff_price<=0){//当前价已更新，您的加价幅度小于300元，请重新出价！
                make_throw(700047);
            }elseif($diff_price>0 && $diff_price<300){
                make_throw(700048);
            }
        }

        if(!$isCus){//重新定义$price(兼容)
            $price = $db_org_price + $add_price;
        }

        if ($price > ($order_info['reserve_price'] * 1.2)) {
            make_throw(700033);
        }

        if ($order_info['status'] != 4) { //竞标中判断
            if($is_auto){//智能出价
                $this->insertIntelBidLog($dealer_id,$order_id,$price,2,$this->exceptionCode[700009]);
            }
            make_throw(700009);
        }

        //获取车商信息
        $carDealerService = new CarDealerService();
        $dealerInfo = $carDealerService->getCarDealer($dealer_id);
        if(empty($dealerInfo)){
            trace('竞标出价，获取蚁巢车商账号失败 dealer_id:'.$dealer_id.' order_id:'.$order_id,'','ERR',true);
            make_throw(360011);
        }

        if($dealerInfo['status']!=1){
            trace('竞标出价，账号已禁用'.var_export($dealerInfo,true),'','ERR',true);
            make_throw(130006);
        }elseif($dealerInfo['level']==0){
            make_throw(360012);
        }
        if(!$isCus){
            if ($org_price != $db_org_price) {//此基价是否已有人出价
                trace($org_price .'!='. $db_org_price,'','ERR',true);
                make_throw(700008);
            }
        }

        if ($order_info['bidding_best_dealer_id'] == $dealer_id) {
            $tmpvar = !$isCus ? $org_price : $order_info['bidding_best_price'];
            if ($tmpvar > $order_info['reserve_price']) {
                if($is_auto){//智能出价
                    $this->insertIntelBidLog($dealer_id,$order_id,$price,2,$this->exceptionCode[700032]);
                }
                //你已出价请等待其它人出价
                make_throw(700032);
            }
        }

        //保证金判断、解冻
        if(($price) > $order_info['bid_best_price']){
            $bailService = new BailService();

            $arr = ['order_id'=>$order_id];
            $keyName = getRedisKeyByCode('REDIS_KEY','100007',$arr);
            $lastBiddingJson = $this->redis->get($keyName);
            $autoBiddingJson = json_decode($lastBiddingJson,true);
            if(!$this->redis->exists($keyName) || is_array($autoBiddingJson)){

                if ($dealerInfo['bail_amount'] < $freeze_price) { //保证金不足不可以出价
                    trace($dealer_id.'保证金不足，不可以出价。','','ERR',true);
                    make_throw(500051);
                }

                if($dealer_id != $autoBiddingJson['dealer_id']){
                    /**冻结当前车商保证金**/
                    try{
                        $freePrice = $bailService->freezeBail($dealer_id,$freeze_price,$order_id);
                        if($freePrice->code!='000000'){
                            make_throw($freePrice->code,$freePrice->message);
                        }
                    }catch(\Exception $e){
                        trace('竞拍出价冻结保证金捕获异常：'.$e->getMessage(),'','ERR',true);
                        make_throw($e->getCode(),$e->getMessage());
                    }
                }
            }else{
                trace('autoBiddingJson'.var_export($autoBiddingJson,true),'','ERR',true);
                make_throw(700052);
            }

            /**即时解冻其他车商保证金(从投标到竞拍结束全程只冻结一名出价最高的车商保证金)**/
            $dealerBailLogService = new DealerBailLogService();
            $dealers = $dealerBailLogService->getUnFreeDealers($order_id,$dealer_id);
            foreach($dealers as $key=>$val){
                $newArr[] = $val['dealer_id'];
            }
            if(!empty($newArr)){
                try{
                    $unfreePrice = $bailService->unfreezeBail(implode(',',$newArr),$order_id);
                    if($unfreePrice->code != '000000'){
                        make_throw(700021);
                    }
                }catch(\Exception $e){
                    make_throw($e->getCode(),$e->getMessage());
                }
            }
        }
        return true;
    }

    /**
     * socket数据类型转换
     * @param $paramers
     * @return array
     */
    private function socketDataConvert($paramers){
            $order_id   = $paramers['order_id'];
            $dealer_id  = $paramers['dealer_id'];

            $orderServ = new OrderService();
            $bidding_info = $orderServ->getBiddingInfo($order_id);
            $bidding_info['dealer_id'] = $dealer_id;
            //当前价
            $bidding_info['current_price'] = $bidding_info['bidding_best_price']>$bidding_info['bid_start_price']? $bidding_info['bidding_best_price']:$bidding_info['bid_start_price'];
            $bidding_info['current_price_show'] = number_format($bidding_info['current_price'],2);
            //交易服务费
            $bidding_info['commision'] = get_commision($bidding_info['bidding_best_price']>0? $bidding_info['bidding_best_price']:$bidding_info['bid_start_price']);
            //交付服务费
            $bidding_info['transfer_fee'] = intval($bidding_info['transfer_fee']);
            //合手价
            $bidding_info['sum_price_show'] = number_format(($bidding_info['current_price']+$bidding_info['commision']+$bidding_info['transfer_fee']),2);

            $bidding_msg = array();
            $bidding_msg['order_id'] = $bidding_info['order_id'];
            $bidding_msg['order_no'] = $bidding_info['order_no'];
            $bidding_msg['bid_start_price'] = $bidding_info['bid_start_price'];
            $bidding_msg['bid_best_price'] = $bidding_info['bid_best_price'];
            $bidding_msg['bidding_best_price'] = $bidding_info['bidding_best_price'];
            $bidding_msg['bid_best_dealer_id'] = $bidding_info['bid_best_dealer_id'];
            $bidding_msg['transfer_fee'] = intval($bidding_info['transfer_fee']);
            $bidding_msg['bidding_best_dealer_id'] = $bidding_info['bidding_best_dealer_id'];
            $bidding_msg['price'] = $bidding_info['price'];
            $bidding_msg['left_time'] = $bidding_info['left_time'];
            $bidding_msg['starttime'] = intval($bidding_info['starttime']);
            $bidding_msg['bidding_start_time'] = intval($bidding_info['bidding_start_time']);
            $bidding_msg['act_elapsed_time'] = intval($bidding_info['act_elapsed_time']);
            $bidding_msg['est_elapsed_time'] = intval($bidding_info['est_elapsed_time']);
            $bidding_msg['bidding_num'] = $bidding_info['bidding_num'];
            $bidding_msg['dealer_num'] = $bidding_info['dealer_num'];
            $bidding_msg['dealer_id'] = $bidding_info['dealer_id'];
            $bidding_msg['current_price'] = $bidding_info['current_price'];
            $bidding_msg['current_price_show'] = $bidding_info['current_price_show'];
            $bidding_msg['commision'] = intval($bidding_info['commision']);
            $bidding_msg['sum_price_show'] = $bidding_info['sum_price_show'];
            return $bidding_msg;
    }

    /**
     * 智能报价相关相处
     * @param $paramers
     * @return void
     */
    private function dealAutobidding($paramers){

            $order_id   = $paramers['order_id'];
            $dealer_id  = $paramers['dealer_id'];
            $org_price  = $paramers['org_price'];
            $add_price  = $paramers['add_price'];
            $dev_type   = $paramers['dev_type'];
            $is_auto    = $paramers['is_auto'];

            //智能报价：更新redis
            $redis = new PhpRedis();
            $order_info = array();
            $order_info['dealer_id'] = $dealer_id;
            $order_info['order_id'] = $order_id;
            $order_info['before_price'] = $org_price;
            $order_info['append_price'] = $add_price;
            $order_info['after_price'] = $org_price+$add_price;
            $order_info['bidding_type'] = $is_auto?2:1; //1人工出价 2机器人出价
            $order_info['create_time'] = time();
            $arr = ['order_id'=>$order_id];
            $keyName = getRedisKeyByCode('REDIS_KEY','100007',$arr);
            $redis->set($keyName,json_encode($order_info),time_left_to_24());

            //如果是智能出价，则更新车商出价次数
            if($is_auto){
                $arr = ['order_id'=>$order_id,'dealer_id'=>$dealer_id];
                $keyName = getRedisKeyByCode('REDIS_KEY','100006',$arr);
                $dealer_info = $redis->get($keyName);
                $dealer_info = json_decode($dealer_info,true);
                $dealer_info['bid_count'] = $dealer_info['bid_count']+1;
                $redis->set($keyName,json_encode($dealer_info),time_left_to_24());
                //更新车商队列
                $arr = ['order_id'=>$order_id];
                $keyName = getRedisKeyByCode('REDIS_KEY','100005',$arr);
                $list = $redis->zrange($keyName,0,-1,true);
                $max = $list?max($list):0;
                $redis->zadd($keyName,$max+1,$dealer_id);
            }
            //------------推送信息给车商
            $arr = ['order_id'=>$order_id];
            $keyName = getRedisKeyByCode('REDIS_KEY','100005',$arr);
            if($redis->exists($keyName)){
                $keyName = getRedisKeyByCode('REDIS_KEY','100012',$arr);
                $res = $redis->scan(null,$keyName,10000);
                $antServ = new AntNestService();
                foreach($res as $key){
                    $arr = $redis->get($key);//获取每一个车商的设置信息
                    $dealer = json_decode($arr,true);
                    if(($org_price+$add_price)>=$dealer['max_price'] && !$dealer['is_pushed']){
                        $this->jpushMsg($redis,$dealer['dealer_id'],$order_id,($org_price+$add_price),$antServ);
                        //标记已推送
                        $dealer['is_pushed'] = 1;
                        $arr = ['order_id'=>$order_id,'dealer_id'=>$dealer['dealer_id']];
                        $keyName = getRedisKeyByCode('REDIS_KEY','100006',$arr);
                        $redis->set($keyName,json_encode($dealer),time_left_to_24());
                    }
                }
            }
    }


}